package com.zzjson.springbootjdbc.repository;

import com.zzjson.springbootjdbc.domain.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCallback;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.util.Collection;
import java.util.Collections;

/**
 * <p>****************************************************************************</p>
 * <p><b>Copyright © 2010-2019 shuncom team All Rights Reserved<b></p>
 * <ul style="margin:15px;">
 * <li>Description : com.zzjson.springbootjdbc.repository</li>
 * <li>Version     : 1.0.0</li>
 * <li>Creation    : 2019年11月04日</li>
 * <li>@author     : zzy0_0</li>
 * </ul>
 * <p>****************************************************************************</p>
 */
@Repository
@Slf4j
public class UserRepository {


	private final DataSource masterDataSource;

	private final DataSource slaveDataSource;
	private final DataSource dataSource;
	private final JdbcTemplate jdbcTemplate;
	private final PlatformTransactionManager platformTransactionManager;

	@Autowired
	public UserRepository(
			DataSource dataSource,
			@Qualifier("masterDataSource") DataSource masterDataSource,
			@Qualifier("slaveDataSource") DataSource slaveDataSource, JdbcTemplate jdbcTemplate, PlatformTransactionManager platformTransactionManager) {
		this.dataSource = dataSource;
		this.masterDataSource = masterDataSource;
		this.slaveDataSource = slaveDataSource;
		this.jdbcTemplate = jdbcTemplate;
		this.platformTransactionManager = platformTransactionManager;
	}

	/**
	 * 手动事物
	 *
	 * @param user
	 * @return
	 */
	public boolean transactionalSave(User user) {
		DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
		TransactionStatus transactionStatus = platformTransactionManager.getTransaction(defaultTransactionDefinition);
		boolean success = jdbcTemplate.execute("INSERT INTO user(id,name) VALUES (?,?)", (PreparedStatementCallback<Boolean>) preparedStatement -> {
			preparedStatement.setInt(1, user.getId());
			preparedStatement.setString(2, user.getName());
			return preparedStatement.executeUpdate() > 0;
		});
		platformTransactionManager.commit(transactionStatus);

		return success;
	}

	public boolean saveUser(User user) {
		boolean success = false;
		Connection connection = null;
		PreparedStatement preparedStatement = null;
		try {
			connection = dataSource.getConnection();
			connection.setAutoCommit(false);
			Savepoint t1 = connection.setSavepoint("t1");
			try {

				save(user);
			} catch (Exception e) {
				connection.rollback(t1);
			}


			preparedStatement = connection.prepareStatement("INSERT INTO user(id,name) VALUES (?,?)");
			preparedStatement.setInt(1, user.getId());
			preparedStatement.setString(2, user.getName());
			int i = preparedStatement.executeUpdate();
			success = i > 0;
			connection.commit();
			connection.releaseSavepoint(t1);
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			close(connection, preparedStatement);

		}
		log.info("[Thread:{} ]save user {}", Thread.currentThread().getName(), user);
		return true;
	}

	private void close(Connection connection, PreparedStatement preparedStatement) {
		if (preparedStatement != null) {
			try {
				preparedStatement.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if (connection != null) {
			try {
				connection.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 注解式事物
	 *
	 * @param user
	 * @return
	 */
	@Transactional
	public Boolean save(User user) {
		return jdbcTemplate.execute("INSERT INTO user(id,name) VALUES (?,?)", (PreparedStatementCallback<Boolean>) preparedStatement -> {
			preparedStatement.setInt(1, user.getId());
			preparedStatement.setString(2, user.getName());
			return preparedStatement.executeUpdate() > 0;
		});
	}

	public Collection<User> findAll() {
		return Collections.emptyList();
	}

}